using Microsoft.Extensions.Logging;
using System.IO.Ports;
using Uantek.Device.Communication.Models;

namespace Uantek.Device.Communication.Protocols.Transports
{
    /// <summary>
    /// 串口通信传输实现
    /// </summary>
    public class SerialTransport : BaseCommunicationTransport
    {
        /// <summary>
        /// 串口对象
        /// </summary>
        private SerialPort? _serialPort;

        /// <summary>
        /// 传输类型
        /// </summary>
        public override string TransportType => "Serial";

        /// <summary>
        /// 端口名称
        /// </summary>
        public string PortName { get; set; } = "COM1";

        /// <summary>
        /// 波特率
        /// </summary>
        public int BaudRate { get; set; } = 9600;

        /// <summary>
        /// 数据位
        /// </summary>
        public int DataBits { get; set; } = 8;

        /// <summary>
        /// 停止位
        /// </summary>
        public StopBits StopBits { get; set; } = StopBits.One;

        /// <summary>
        /// 校验位
        /// </summary>
        public Parity Parity { get; set; } = Parity.None;

        /// <summary>
        /// 握手协议
        /// </summary>
        public Handshake Handshake { get; set; } = Handshake.None;

        /// <summary>
        /// 读取超时时间（毫秒）
        /// </summary>
        public int ReadTimeout { get; set; } = 5000;

        /// <summary>
        /// 写入超时时间（毫秒）
        /// </summary>
        public int WriteTimeout { get; set; } = 5000;

        /// <summary>
        /// 缓冲区大小
        /// </summary>
        public int BufferSize { get; set; } = 4096;

        /// <summary>
        /// 接收缓冲区大小
        /// </summary>
        public int ReceiveBufferSize { get; set; } = 4096;

        /// <summary>
        /// 发送缓冲区大小
        /// </summary>
        public int SendBufferSize { get; set; } = 4096;

        /// <summary>
        /// DTR信号控制
        /// </summary>
        public bool DtrEnable { get; set; } = false;

        /// <summary>
        /// RTS信号控制
        /// </summary>
        public bool RtsEnable { get; set; } = false;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="logger">日志记录器</param>
        public SerialTransport(ILogger<SerialTransport>? logger = null) : base(logger)
        {
        }

        /// <summary>
        /// 连接的具体实现
        /// </summary>
        /// <param name="connectionParameters">连接参数</param>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>连接结果</returns>
        protected override async Task<CommunicationResult> ConnectInternalAsync(Dictionary<string, object> connectionParameters, CancellationToken cancellationToken)
        {
            try
            {
                // 获取连接参数
                PortName = GetParameter<string>(connectionParameters, "PortName", PortName);
                BaudRate = GetParameter<int>(connectionParameters, "BaudRate", BaudRate);
                DataBits = GetParameter<int>(connectionParameters, "DataBits", DataBits);
                StopBits = GetParameter<StopBits>(connectionParameters, "StopBits", StopBits);
                Parity = GetParameter<Parity>(connectionParameters, "Parity", Parity);
                Handshake = GetParameter<Handshake>(connectionParameters, "Handshake", Handshake);
                ReadTimeout = GetParameter<int>(connectionParameters, "ReadTimeout", ReadTimeout);
                WriteTimeout = GetParameter<int>(connectionParameters, "WriteTimeout", WriteTimeout);
                BufferSize = GetParameter<int>(connectionParameters, "BufferSize", BufferSize);
                ReceiveBufferSize = GetParameter<int>(connectionParameters, "ReceiveBufferSize", ReceiveBufferSize);
                SendBufferSize = GetParameter<int>(connectionParameters, "SendBufferSize", SendBufferSize);
                DtrEnable = GetParameter<bool>(connectionParameters, "DtrEnable", DtrEnable);
                RtsEnable = GetParameter<bool>(connectionParameters, "RtsEnable", RtsEnable);

                LogDebug("开始串口连接，端口: {PortName}，波特率: {BaudRate}，数据位: {DataBits}，停止位: {StopBits}，校验位: {Parity}", 
                    PortName, BaudRate, DataBits, StopBits, Parity);

                // 检查端口是否可用
                var availablePorts = SerialPort.GetPortNames();
                if (!availablePorts.Contains(PortName))
                {
                    LogWarning("串口不存在，端口: {PortName}，可用端口: {AvailablePorts}", PortName, string.Join(", ", availablePorts));
                    return CommunicationResult.CreateFailure($"串口不存在: {PortName}", "PortNotFound");
                }

                // 创建串口对象
                _serialPort = new SerialPort(PortName, BaudRate, Parity, DataBits, StopBits)
                {
                    Handshake = Handshake,
                    ReadTimeout = ReadTimeout,
                    WriteTimeout = WriteTimeout,
                    ReadBufferSize = ReceiveBufferSize,
                    WriteBufferSize = SendBufferSize,
                    DtrEnable = DtrEnable,
                    RtsEnable = RtsEnable
                };

                // 打开串口
                _serialPort.Open();

                if (!_serialPort.IsOpen)
                {
                    return CommunicationResult.CreateFailure($"串口打开失败: {PortName}", "PortOpenFailed");
                }

                // 清空缓冲区
                _serialPort.DiscardInBuffer();
                _serialPort.DiscardOutBuffer();

                LogInformation("串口连接成功，端口: {PortName}，波特率: {BaudRate}", PortName, BaudRate);
                await Task.CompletedTask;
                return CommunicationResult.CreateSuccess("串口连接成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "串口连接时发生异常，端口: {PortName}", PortName);
                
                // 清理资源
                CleanupConnection();
                
                return CommunicationResult.CreateFailure($"串口连接异常: {ex.Message}", "ConnectionException", ex);
            }
        }

        /// <summary>
        /// 断开连接的具体实现
        /// </summary>
        /// <returns>断开结果</returns>
        protected override async Task<CommunicationResult> DisconnectInternalAsync()
        {
            try
            {
                LogDebug("开始断开串口连接，端口: {PortName}", PortName);

                CleanupConnection();

                LogInformation("串口连接断开成功，端口: {PortName}", PortName);
                await Task.CompletedTask;
                return CommunicationResult.CreateSuccess("串口连接断开成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "断开串口连接时发生异常，端口: {PortName}", PortName);
                return CommunicationResult.CreateFailure($"断开串口连接异常: {ex.Message}", "DisconnectionException", ex);
            }
        }

        /// <summary>
        /// 发送数据的具体实现
        /// </summary>
        /// <param name="data">数据</param>
        /// <returns>发送结果</returns>
        protected override CommunicationResult SendDataInternal(byte[] data)
        {
            try
            {
                if (_serialPort == null || !_serialPort.IsOpen)
                {
                    return CommunicationResult.CreateFailure("串口未打开", "PortNotOpen");
                }

                LogDebug("发送串口数据，端口: {PortName}，长度: {Length}，数据: {Data}", PortName, data.Length, Convert.ToHexString(data));

                _serialPort.Write(data, 0, data.Length);

                LogDebug("串口数据发送成功，端口: {PortName}，长度: {Length}", PortName, data.Length);
                return CommunicationResult.CreateSuccess("串口数据发送成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "发送串口数据时发生异常，端口: {PortName}", PortName);
                return CommunicationResult.CreateFailure($"发送串口数据异常: {ex.Message}", "SendException", ex);
            }
        }

        /// <summary>
        /// 配置参数的具体实现
        /// </summary>
        /// <param name="parameters">参数</param>
        /// <returns>配置结果</returns>
        protected override async Task<CommunicationResult> ConfigureInternalAsync(Dictionary<string, object> parameters)
        {
            try
            {
                LogDebug("开始配置串口传输参数，端口: {PortName}", PortName);

                // 更新配置参数
                ReadTimeout = GetParameter<int>(parameters, "ReadTimeout", ReadTimeout);
                WriteTimeout = GetParameter<int>(parameters, "WriteTimeout", WriteTimeout);
                BufferSize = GetParameter<int>(parameters, "BufferSize", BufferSize);
                ReceiveBufferSize = GetParameter<int>(parameters, "ReceiveBufferSize", ReceiveBufferSize);
                SendBufferSize = GetParameter<int>(parameters, "SendBufferSize", SendBufferSize);
                DtrEnable = GetParameter<bool>(parameters, "DtrEnable", DtrEnable);
                RtsEnable = GetParameter<bool>(parameters, "RtsEnable", RtsEnable);

                // 如果已连接，更新串口的设置
                if (_serialPort != null && _serialPort.IsOpen)
                {
                    _serialPort.ReadTimeout = ReadTimeout;
                    _serialPort.WriteTimeout = WriteTimeout;
                    _serialPort.ReadBufferSize = ReceiveBufferSize;
                    _serialPort.WriteBufferSize = SendBufferSize;
                    _serialPort.DtrEnable = DtrEnable;
                    _serialPort.RtsEnable = RtsEnable;
                }

                LogDebug("串口传输参数配置完成，端口: {PortName}", PortName);
                await Task.CompletedTask;
                return CommunicationResult.CreateSuccess("串口传输参数配置成功");
            }
            catch (Exception ex)
            {
                LogError(ex, "配置串口传输参数时发生异常，端口: {PortName}", PortName);
                return CommunicationResult.CreateFailure($"配置串口传输参数异常: {ex.Message}", "ConfigurationException", ex);
            }
        }

        /// <summary>
        /// 数据接收循环
        /// </summary>
        /// <param name="cancellationToken">取消令牌</param>
        /// <returns>任务</returns>
        protected override async Task ReceiveDataLoopAsync(CancellationToken cancellationToken)
        {
            var buffer = new byte[BufferSize];

            try
            {
                LogDebug("开始串口数据接收循环，端口: {PortName}，缓冲区大小: {BufferSize}", PortName, BufferSize);

                while (!cancellationToken.IsCancellationRequested && IsConnected && _serialPort != null && _serialPort.IsOpen)
                {
                    try
                    {
                        // 检查是否有数据可读
                        if (_serialPort.BytesToRead == 0)
                        {
                            await Task.Delay(10, cancellationToken);
                            continue;
                        }

                        var bytesToRead = Math.Min(_serialPort.BytesToRead, buffer.Length);
                        var bytesRead = _serialPort.Read(buffer, 0, bytesToRead);

                        if (bytesRead > 0)
                        {
                            var data = new byte[bytesRead];
                            Array.Copy(buffer, 0, data, 0, bytesRead);

                            LogDebug("接收到串口数据，端口: {PortName}，长度: {Length}，数据: {Data}", PortName, bytesRead, Convert.ToHexString(data));

                            OnDataReceived(data);
                        }
                    }
                    catch (OperationCanceledException) when (cancellationToken.IsCancellationRequested)
                    {
                        LogDebug("串口数据接收循环被取消，端口: {PortName}", PortName);
                        break;
                    }
                    catch (TimeoutException)
                    {
                        // 读取超时是正常的，继续循环
                        continue;
                    }
                    catch (InvalidOperationException)
                    {
                        LogDebug("串口已关闭，退出接收循环，端口: {PortName}", PortName);
                        break;
                    }
                    catch (Exception ex)
                    {
                        LogError(ex, "串口数据接收时发生异常，端口: {PortName}", PortName);
                        await Task.Delay(1000, cancellationToken); // 等待一段时间后重试
                    }
                }

                LogDebug("串口数据接收循环结束，端口: {PortName}", PortName);
            }
            catch (Exception ex)
            {
                LogError(ex, "串口数据接收循环发生异常，端口: {PortName}", PortName);
            }
        }

        /// <summary>
        /// 构建连接信息
        /// </summary>
        /// <param name="connectionParameters">连接参数</param>
        /// <returns>连接信息</returns>
        protected override string BuildConnectionInfo(Dictionary<string, object> connectionParameters)
        {
            var portName = GetParameter<string>(connectionParameters, "PortName", "COM1");
            var baudRate = GetParameter<int>(connectionParameters, "BaudRate", 9600);
            var dataBits = GetParameter<int>(connectionParameters, "DataBits", 8);
            var stopBits = GetParameter<StopBits>(connectionParameters, "StopBits", StopBits.One);
            var parity = GetParameter<Parity>(connectionParameters, "Parity", Parity.None);
            
            return $"Serial://{portName}?baudrate={baudRate}&databits={dataBits}&stopbits={stopBits}&parity={parity}";
        }

        /// <summary>
        /// 释放资源的具体实现
        /// </summary>
        protected override void DisposeInternal()
        {
            CleanupConnection();
        }

        #region 私有方法

        /// <summary>
        /// 清理连接资源
        /// </summary>
        private void CleanupConnection()
        {
            try
            {
                if (_serialPort != null)
                {
                    if (_serialPort.IsOpen)
                    {
                        _serialPort.Close();
                    }
                    _serialPort.Dispose();
                    _serialPort = null;
                }

                LogDebug("串口连接资源清理完成，端口: {PortName}", PortName);
            }
            catch (Exception ex)
            {
                LogError(ex, "清理串口连接资源时发生异常，端口: {PortName}", PortName);
            }
        }

        #endregion

        #region 公共方法

        /// <summary>
        /// 获取可用的串口列表
        /// </summary>
        /// <returns>可用串口列表</returns>
        public static string[] GetAvailablePorts()
        {
            return SerialPort.GetPortNames();
        }

        /// <summary>
        /// 检查指定串口是否可用
        /// </summary>
        /// <param name="portName">端口名称</param>
        /// <returns>是否可用</returns>
        public static bool IsPortAvailable(string portName)
        {
            return SerialPort.GetPortNames().Contains(portName);
        }

        /// <summary>
        /// 获取串口状态信息
        /// </summary>
        /// <returns>状态信息</returns>
        public Dictionary<string, object> GetPortStatus()
        {
            var status = new Dictionary<string, object>
            {
                ["TransportType"] = TransportType,
                ["PortName"] = PortName,
                ["IsConnected"] = IsConnected,
                ["BaudRate"] = BaudRate,
                ["DataBits"] = DataBits,
                ["StopBits"] = StopBits.ToString(),
                ["Parity"] = Parity.ToString(),
                ["Handshake"] = Handshake.ToString(),
                ["ReadTimeout"] = ReadTimeout,
                ["WriteTimeout"] = WriteTimeout,
                ["BufferSize"] = BufferSize,
                ["ReceiveBufferSize"] = ReceiveBufferSize,
                ["SendBufferSize"] = SendBufferSize,
                ["DtrEnable"] = DtrEnable,
                ["RtsEnable"] = RtsEnable
            };

            if (_serialPort != null && _serialPort.IsOpen)
            {
                try
                {
                    status["BytesToRead"] = _serialPort.BytesToRead;
                    status["BytesToWrite"] = _serialPort.BytesToWrite;
                    status["CDHolding"] = _serialPort.CDHolding;
                    status["CtsHolding"] = _serialPort.CtsHolding;
                    status["DsrHolding"] = _serialPort.DsrHolding;
                }
                catch (Exception ex)
                {
                    status["StatusError"] = ex.Message;
                }
            }

            return status;
        }

        /// <summary>
        /// 清空接收缓冲区
        /// </summary>
        public void ClearReceiveBuffer()
        {
            try
            {
                if (_serialPort != null && _serialPort.IsOpen)
                {
                    _serialPort.DiscardInBuffer();
                    LogDebug("接收缓冲区已清空，端口: {PortName}", PortName);
                }
            }
            catch (Exception ex)
            {
                LogError(ex, "清空接收缓冲区时发生异常，端口: {PortName}", PortName);
            }
        }

        /// <summary>
        /// 清空发送缓冲区
        /// </summary>
        public void ClearSendBuffer()
        {
            try
            {
                if (_serialPort != null && _serialPort.IsOpen)
                {
                    _serialPort.DiscardOutBuffer();
                    LogDebug("发送缓冲区已清空，端口: {PortName}", PortName);
                }
            }
            catch (Exception ex)
            {
                LogError(ex, "清空发送缓冲区时发生异常，端口: {PortName}", PortName);
            }
        }

        /// <summary>
        /// 设置串口信号线
        /// </summary>
        /// <param name="dtr">DTR信号</param>
        /// <param name="rts">RTS信号</param>
        public void SetSignals(bool dtr, bool rts)
        {
            try
            {
                if (_serialPort != null && _serialPort.IsOpen)
                {
                    _serialPort.DtrEnable = dtr;
                    _serialPort.RtsEnable = rts;
                    DtrEnable = dtr;
                    RtsEnable = rts;
                    LogDebug("串口信号线设置完成，端口: {PortName}，DTR: {DTR}，RTS: {RTS}", PortName, dtr, rts);
                }
            }
            catch (Exception ex)
            {
                LogError(ex, "设置串口信号线时发生异常，端口: {PortName}", PortName);
            }
        }

        #endregion
    }
}